//其他服务通过调用这个注册client来向服务中心注册
package registry

import (
	"bytes"
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"net/url"
	"sync"
)

//注册服务
func RegisterService(r Registration) error {
	//启动此服务心跳响应server
	HeartbeatURL, err := url.Parse(r.HeartbeatURL)
	if err != nil {
		return fmt.Errorf("Can not Use this %s for HeartbeatURL", HeartbeatURL)
	}
	http.HandleFunc(HeartbeatURL.Path, func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
	})

	//启动依赖更新server
	serviceUpdateURL, err := url.Parse(r.ServiceUpdateURL)
	if err != nil {
		return fmt.Errorf("Can not Use this %s for serviceUpdateURL", serviceUpdateURL)
	}
	http.Handle(serviceUpdateURL.Path, &serviceUpdateHandler{})

	//发送本服务的注册请求
	buf := new(bytes.Buffer)
	enc := json.NewEncoder(buf)
	if err := enc.Encode(r); err != nil {
		return err
	}
	res, err := http.Post(ServicesURL, "application/json", buf)
	if err != nil {
		return err
	}
	if res.StatusCode != http.StatusOK {
		return fmt.Errorf("Failed to register service. Registry service"+
			"responded with code %v", res.StatusCode)
	}
	return nil
}

//serviceUpdateHandler是为了实现Handler接口
type serviceUpdateHandler struct {
}

func (suh serviceUpdateHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		w.WriteHeader(http.StatusMethodNotAllowed)
		return
	}
	dec := json.NewDecoder(r.Body)
	var p patch
	if err := dec.Decode(&p); err != nil {
		log.Println(err)
		w.WriteHeader(http.StatusBadGateway)
		return
	}
	fmt.Printf("Updated received %v\n", p)
	prov.Update(p)
}

//关闭本服务
func ShutdownService(url string) error {
	//构造默认请求，请求体填充url
	req, err := http.NewRequest(http.MethodDelete, ServicesURL,
		bytes.NewBuffer([]byte(url)))
	if err != nil {
		return err
	}
	//更新设置请求头
	req.Header.Add("Content-Type", "text/plain")
	// 默认发送
	res, err := http.DefaultClient.Do(req)
	if err != nil {
		return err
	}
	//检查响应码是否有误
	if res.StatusCode != http.StatusOK {
		return fmt.Errorf("Failed to del register service."+
			"Registry service responded with code %v", res.StatusCode)
	}
	return nil
}

//依赖项
type providers struct {
	services map[ServiceName][]string
	mutex    *sync.RWMutex
}

//维护的依赖项变量
var prov = providers{
	services: make(map[ServiceName][]string),
	mutex:    new(sync.RWMutex),
}

func (p providers) Update(pat patch) {
	p.mutex.Lock()
	defer p.mutex.Unlock()
	//添加
	for _, patchEntry := range pat.Added {
		if _, exist := p.services[patchEntry.Name]; !exist {
			p.services[patchEntry.Name] = make([]string, 0)
		}
		p.services[patchEntry.Name] = append(p.services[patchEntry.Name],
			patchEntry.URL)
	}
	//删除
	for _, patchEntry := range pat.Removed {
		if providerURLs, exist := p.services[patchEntry.Name]; exist {
			for i := range providerURLs {
				if providerURLs[i] == patchEntry.URL {
					p.services[patchEntry.Name] = append(providerURLs[0:i],
						providerURLs[i+1:]...)
				}
			}
		}

	}
}

//查询某个依赖的URL列表
func (p providers) getURLs(name ServiceName) ([]string, error) {
	providers, exist := p.services[name]

	if !exist {
		emp := make([]string, 0)
		return emp, fmt.Errorf("No providers available for service &v", name)
	}
	return providers, nil
}

func GetProviderURLs(name ServiceName) ([]string, error) {
	return prov.getURLs(name)
}
